package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.dao.SecondCollectionConfigDao;
import com.sc.nft.dao.SecondCollectionDao;
import com.sc.nft.dao.SecondOrderDao;
import com.sc.nft.entity.DisassemblyHistoryLog;
import com.sc.nft.entity.SecondCollectionConfig;
import com.sc.nft.entity.SecondOrder;
import com.sc.nft.entity.dto.SecondaryMarketSearchDTO;
import com.sc.nft.entity.vo.CollectionSimpleVO;
import com.sc.nft.entity.vo.SecondaryMarketSearchVO;
import com.sc.nft.enums.MarketTypeEnum;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.mapper.SecondCollectionMapper;
import com.sc.nft.service.SecondCollectionConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 二级藏品配置表服务接口实现
 *
 * @author kancy
 * @description 由 Mybatisplus Code Generator 创建
 * @since 2022-10-03 16:53:14
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SecondCollectionConfigServiceImpl implements SecondCollectionConfigService {

    private final SecondCollectionConfigDao secondCollectionConfigDao;
    private final SecondOrderDao secondOrderDao;
    private final RedisTemplate redisTemplate;
    private final SecondCollectionDao secondCollectionDao;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void priceUp() {
        List<SecondCollectionConfig> secondCollectionConfigList = secondCollectionConfigDao.getListByStatusAndMarketType(MarketTypeEnum.BRAND_INCUBATION);
        for (SecondCollectionConfig secondCollectionConfig : secondCollectionConfigList) {

            if (secondCollectionConfig.getUpRatio().compareTo(BigDecimal.ZERO) == 0) {
                continue;
            }

            secondCollectionConfig.setMinPrice(secondCollectionConfig.getMaxPrice());
            secondCollectionConfig.setMaxPrice(secondCollectionConfig.getMaxPrice().add(secondCollectionConfig.getMaxPrice().multiply(secondCollectionConfig.getUpRatio())));
            //如果开启拆配
            if (secondCollectionConfig.getIsDisassembly()) {
                //拆配总额 = 起始金额 * 倍数
                BigDecimal disassemblySum = secondCollectionConfig.getStartPrice().multiply(Convert.toBigDecimal(secondCollectionConfig.getDisassemblyMultiple()));

                //String days=  Math.log((拆配/发行))/Math.log(1+增长率)
                double log = BigDecimal.ONE.add(secondCollectionConfig.getUpRatio()).doubleValue();
                double log2 = disassemblySum.divide(secondCollectionConfig.getMaxPrice(), 8, BigDecimal.ROUND_DOWN).stripTrailingZeros().doubleValue();
                //拆配剩余天数
                secondCollectionConfig.setLastDisassemblyDay(Convert.toInt(Convert.toBigDecimal(Math.log(log2)).divide(Convert.toBigDecimal(Math.log(log)), 0, BigDecimal.ROUND_UP).stripTrailingZeros()));
                // 累积涨幅 = (当前价格 - 发行价)/ 发行价
                BigDecimal subtract = secondCollectionConfig.getMaxPrice().subtract(secondCollectionConfig.getStartPrice());
                BigDecimal cumulativeIncrease = subtract.divide(secondCollectionConfig.getStartPrice(), 4, BigDecimal.ROUND_DOWN).stripTrailingZeros();
                secondCollectionConfig.setCumulativeIncrease(cumulativeIncrease);


                //判断拆配当前金额是否大于拆配总额
                if (secondCollectionConfig.getMaxPrice().compareTo(disassemblySum) > -1) {//如果是大于等级 就是触发拆配
                    //最小数据
                    secondCollectionConfig.setMinPrice(secondCollectionConfig.getStartPrice());
                    //初始话所有数据最高价
                    secondCollectionConfig.setMaxPrice(secondCollectionConfig.getStartPrice().add(secondCollectionConfig.getStartPrice().multiply(secondCollectionConfig.getUpRatio())));
                    //初始累积涨幅
                    secondCollectionConfig.setCumulativeIncrease(secondCollectionConfig.getUpRatio());
                    //重新计算
                    double initLog = disassemblySum.divide(secondCollectionConfig.getMaxPrice(), 8, BigDecimal.ROUND_DOWN).stripTrailingZeros().doubleValue();
                    //初始化拆配天数
                    secondCollectionConfig.setLastDisassemblyDay(Convert.toInt(Convert.toBigDecimal(Math.log(initLog)).divide(Convert.toBigDecimal(Math.log(log)), 0, BigDecimal.ROUND_UP).stripTrailingZeros()));

                    //插入拆配历史记录表
                    DisassemblyHistoryLog disassemblyHistoryLog = new DisassemblyHistoryLog();
                    disassemblyHistoryLog.setCollectionId(secondCollectionConfig.getCollectionId());
                    disassemblyHistoryLog.setIsSettleAccounts(Boolean.FALSE);
                    disassemblyHistoryLog.setCharge(secondCollectionConfig.getCharge());
                    disassemblyHistoryLog.setDisassemblySum(disassemblySum);
                    disassemblyHistoryLog.setStartPrice(secondCollectionConfig.getStartPrice());
                    disassemblyHistoryLog.insert();
                }
            }
            secondCollectionConfig.updateById();
        }
    }

    @Override
    public void freeMarketReference() {
        List<SecondCollectionConfig> secondCollectionConfigs = secondCollectionConfigDao.freeMarketReference();
        secondCollectionConfigs.forEach(secondCollectionConfig -> {
            // 根据藏品id,获取那一天最后一条成交数据,成交价格计算好以后进行更新.作为配置使用
            SecondOrder secondOrder = secondOrderDao.getOrderBeforeDayLastDealData(secondCollectionConfig.getCollectionId());
            if (BeanUtil.isEmpty(secondOrder)) {
                return;
            }
            BigDecimal buyPrice = secondOrder.getBuyPrice();
            SecondCollectionConfig data = new SecondCollectionConfig();
            data.setFloatingPrice(buyPrice);
//            // 向下涨幅
//            BigDecimal freeDownRatio =(Convert.toBigDecimal(100).subtract(secondCollectionConfig.getFreeDownRatio())).divide(Convert.toBigDecimal(100), 2, BigDecimal.ROUND_DOWN);
//            // 向上涨幅
//            BigDecimal freeUpRatio = (Convert.toBigDecimal(100).add(secondCollectionConfig.getFreeUpRatio())).divide(Convert.toBigDecimal(100), 2, BigDecimal.ROUND_DOWN);
//            data.setMinPrice(freeDownRatio.multiply(buyPrice));
//            data.setMaxPrice(freeUpRatio.multiply(buyPrice));
            secondCollectionConfigDao.saveFloatingPrice(data, secondCollectionConfig.getId());
        });
    }

    @Override
    public Page<CollectionSimpleVO> getPageSecondaryMarketCollection(Integer pageNo, Integer pageSize) {
        return secondOrderDao.getPageSecondaryMarketCollection(pageNo, pageSize);
    }

    /**
     * 搜索功能.检索sc_second_collection_config表和sc_digital_collection表的关联
     * 根据marketType进行条件区分检索
     * 返回对象SecondaryMarketSearchVO
     */
    @Override
    public IPage<SecondaryMarketSearchVO> marketSearch(SecondaryMarketSearchDTO request) {
        return secondOrderDao.marketSearch(request);
    }

    @Override
    public SecondCollectionConfig getByCollectionAndType(Long collectionId, MarketTypeEnum marketType) {
        return secondCollectionConfigDao.getByCollectionIdAndMarketType(collectionId, marketType);
    }

    @Override
    public void consensusUpPrice(SecondCollectionConfig secondCollectionConfig) {
        String key = RedisKeyEnum.CONSENSUS_UP_PRICE_LOCK.getKey()+secondCollectionConfig.getCollectionId().toString();

        Object o = redisTemplate.opsForValue().get(key);
        if(ObjectUtil.isNotNull(o)&&Integer.parseInt(o.toString())>=5) {
            return;
        }
        BigDecimal maxPrice = secondCollectionConfig.getStartPrice().multiply(BigDecimal.valueOf(2));
        if (NumberUtil.isGreaterOrEqual(secondCollectionConfig.getConsensusMinPrice(),maxPrice)) {
            return;
        }
        BigDecimal consensusMinPrice = secondCollectionDao.getConsensusMinPriceByCollectionId(secondCollectionConfig.getCollectionId());
        double subPriceRatio  = secondCollectionConfig.getConsensusUpTime()<2?0.1:0.05;
        if(NumberUtil.isGreaterOrEqual(consensusMinPrice.subtract(secondCollectionConfig.getConsensusMinPrice()),secondCollectionConfig.getConsensusMinPrice().multiply(BigDecimal.valueOf(subPriceRatio)))){
            if(!redisTemplate.hasKey(key)){
                redisTemplate.opsForValue().increment(key);
                redisTemplate.expire(key,1, TimeUnit.DAYS);
            }else{
                redisTemplate.opsForValue().increment(key);
            }
            secondCollectionConfig.setConsensusMinPrice(NumberUtil.min(secondCollectionConfig.getConsensusMinPrice().add(secondCollectionConfig.getConsensusMinPrice().multiply(BigDecimal.valueOf(0.025)).setScale(2,BigDecimal.ROUND_HALF_UP)),maxPrice));
            secondCollectionConfig.setConsensusUpTime(secondCollectionConfig.getConsensusUpTime()+1);
            secondCollectionConfig.updateById();
        }
    }

    @Override
    public void consensusDownPrice(SecondCollectionConfig secondCollectionConfig) {
        BigDecimal minPrice = secondCollectionConfig.getStartPrice().divide(BigDecimal.valueOf(2),2, RoundingMode.HALF_UP);
        if (NumberUtil.isLessOrEqual(secondCollectionConfig.getConsensusMinPrice(),minPrice)) {
            return;
        }
        Integer count = secondCollectionDao.getConsensusCountByCollectionIdAndPrice(secondCollectionConfig.getCollectionId(),secondCollectionConfig.getConsensusMinPrice());
        if(count>=200){
            Integer countByCollectionIdAndTime = secondOrderDao.getConsensusCountByCollectionIdAndTime(secondCollectionConfig.getCollectionId(), DateTime.now().offset(DateField.HOUR_OF_DAY, -12));
            if(countByCollectionIdAndTime<=20){
                secondCollectionConfig.setConsensusMinPrice(NumberUtil.max(secondCollectionConfig.getConsensusMinPrice().subtract(secondCollectionConfig.getConsensusMinPrice().multiply(BigDecimal.valueOf(0.01)).setScale(2,BigDecimal.ROUND_HALF_UP)),minPrice));
                secondCollectionConfig.setConsensusDownTime(secondCollectionConfig.getConsensusDownTime()+1);
                secondCollectionConfig.updateById();
            }

        }
    }

}